/**
 * 
 */
package br.flf.webchat.negocio.impl;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import javax.faces.FacesException;

import br.flf.webchat.entidades.Cliente;
import br.flf.webchat.entidades.DialogoTO;
import br.flf.webchat.entidades.Funcionario;
import br.flf.webchat.excecoes.NegocioException;
import br.flf.webchat.mbean.utils.StatusAtendimento;
import br.flf.webchat.negocio.IControleAtendimentoClienteBO;
import br.flf.webchat.negocio.IControleAtendimentoFuncionarioBO;

/**
 * @author Nathan
 * 
 */
public class ControleAtendimentoBO implements IControleAtendimentoClienteBO,
		IControleAtendimentoFuncionarioBO {
	// -------------------------------------------Constantes
	// --------------------------------------------Atributos

	private List<Funcionario> listaFuncionarios;
	private LinkedList<Cliente> listaClientes;
	private static ControleAtendimentoBO instance;

	// -------------------------------------Metodos Publicos
	/** {@inheritDoc} */
	@Override
	public void cadastrarClienteParaAtendimento(Cliente cliente)
			throws NegocioException {

		if (getListaClientes().contains(cliente)) {
			throw new NegocioException("O nome do cliente ja existe.");
		}
		cliente.setStatusAtendimento(StatusAtendimento.PARADO);
		getListaClientes().addLast(cliente);

	}

	/** {@inheritDoc} */
	@Override
	public void cadastrarFuncionarioParaAtendimento(Funcionario funcionario)
			throws FacesException {
		funcionario.setStatusAtendimento(StatusAtendimento.PARADO);
		getListaFuncionarios().add(funcionario);

	}

	/** {@inheritDoc} */
	@Override
	public void cancelarAtendimento(Cliente cliente) {
		synchronized (listaClientes) {
			getListaClientes().remove(cliente);
		}
		

	}

	/** {@inheritDoc} */
	@Override
	public void cancelarAtendimento(Funcionario funcionario) {
		funcionario.setStatusAtendimento(StatusAtendimento.CANCELADO);
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @throws NegocioException
	 *             - Ao ocorrer um erro de negocio
	 */
	@Override
	public synchronized DialogoTO iniciarAtendimento(Funcionario funcionario)
			throws NegocioException {

		synchronized (funcionario) {

			if (getListaClientes().isEmpty()) {
				throw new NegocioException("Lista de clientes vazia");
			}
			Cliente cliente = getListaClientes().poll();
			synchronized (cliente) {

				getListaFuncionarios().remove(funcionario);
				DialogoTO dialogoTO = new DialogoTO();
				dialogoTO.setCliente(cliente);
				dialogoTO.setFuncionario(funcionario);
				funcionario.setDialogoTO(dialogoTO);
				cliente.setDialogoTO(dialogoTO);
				funcionario.setStatusAtendimento(StatusAtendimento.INICIADO);
				cliente.setStatusAtendimento(StatusAtendimento.INICIADO);
				return dialogoTO;
			}
		}
	}

	/** {@inheritDoc} */
	@Override
	public Integer obterPosicaoCliente(Cliente clienteParam) {
		int i = 0;

		for (Cliente cliente : listaClientes) {
			if (clienteParam.equals(cliente)) {
				break;
			}
			i++;
		}
		return i;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @seebr.flf.webchat.negocio.IControleAtendimentoFuncionarioBO#
	 * obterListaDeClientesParaAtendimento()
	 */
	@Override
	public List<Cliente> obterListaDeClientesParaAtendimento() {
		
		return getListaClientes();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * br.flf.webchat.negocio.IControleAtendimentoFuncionarioBO#pararAtendimento
	 * (br.flf.webchat.entidades.Funcionario)
	 */
	@Override
	public void pararAtendimento(Funcionario funcionario) {
		funcionario.setStatusAtendimento(StatusAtendimento.PARADO);
		getListaFuncionarios().remove(funcionario);
	}

	// -------------------------------------Metodos Privados
	// ----------------------------------------Gets and Sets

	public static IControleAtendimentoClienteBO getControleAtendimentoCliente() {
		if (instance == null) {
			instance = new ControleAtendimentoBO();
		}

		return instance;
	}

	public static IControleAtendimentoFuncionarioBO getControleAtendimentoFuncionario() {
		if (instance == null) {
			instance = new ControleAtendimentoBO();
		}

		return instance;
	}

	/**
	 * @return the listaFuncionarios
	 */
	public List<Funcionario> getListaFuncionarios() {
		if (listaFuncionarios == null) {
			listaFuncionarios = new ArrayList<Funcionario>();
		}
		return listaFuncionarios;
	}

	/**
	 * @param listaFuncionarios
	 *            the listaFuncionarios to set
	 */
	public void setListaFuncionarios(List<Funcionario> listaFuncionarios) {
		this.listaFuncionarios = listaFuncionarios;
	}

	/**
	 * @return the listaClientes
	 */
	public LinkedList<Cliente> getListaClientes() {
		if (listaClientes == null) {
			listaClientes = new LinkedList<Cliente>();
		}
		return listaClientes;
	}

	/**
	 * @param listaClientes
	 *            the listaClientes to set
	 */
	public void setListaClientes(LinkedList<Cliente> listaClientes) {
		this.listaClientes = listaClientes;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @seebr.flf.webchat.negocio.IControleAtendimentoFuncionarioBO#
	 * obterFuncionarioProntoParaAtendimento()
	 */
	@Override
	public synchronized Funcionario obterFuncionarioProntoParaAtendimento()
			throws NegocioException {
		for (Funcionario funcionario : getListaFuncionarios()) {
			if (StatusAtendimento.INICIADO.equals(funcionario
					.getStatusAtendimento())) {
				return funcionario;
			}
		}
		throw new NegocioException("Nao ha funcionarios em atendimento.");
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * br.flf.webchat.negocio.IControleAtendimentoClienteBO#obterPrimeiroCliente
	 * ()
	 */
	@Override
	public synchronized Cliente obterPrimeiroCliente() {

		return getListaClientes().pollFirst();
	}

}
